package com.kapuscinski.saferoute.logic;

import com.kapuscinski.saferoute.SettingsActivity;

import android.app.Activity;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.location.GpsStatus;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.util.Log;

public class RoughnessLocationMonitor {

	public interface RoughnessLocationListener {
		public void onAccelerationChange(float value);
		
		public void onLocationChange(Location location);
		
		public void onRoughnessDetected(Location location, float acceleration);

		public void onGpsStatusChange(GpsStatus gpsStatus);
	}
	
	private static final String TAG = "RoughnessLocationMonitor";

	private LocationManager locationManager;
	private SensorManager sensorManager;
	private Sensor accelerometer;
	private RoughnessLocationListener listener;

	private long roughnessTime;
	private int flag;
	private Location prevLocation, currLocation;
	private float thresholdSmall, yValue;

	public RoughnessLocationMonitor(Activity activity) {
		locationManager = (LocationManager) activity
				.getSystemService(Activity.LOCATION_SERVICE);
		locationManager.addGpsStatusListener(gpsListener);
		sensorManager = (SensorManager) activity
				.getSystemService(Activity.SENSOR_SERVICE);
		accelerometer = sensorManager
				.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);
		readPreferences(activity);
	}

	private void readPreferences(Activity activity) {
		SharedPreferences preferences = activity.getSharedPreferences(
				SettingsActivity.KEY_FILENAME, Activity.MODE_PRIVATE);
		preferences
				.registerOnSharedPreferenceChangeListener(preferenceListener);
		thresholdSmall = preferences.getFloat(
				SettingsActivity.KEY_THRESHOLD_SMALL,
				SettingsActivity.DEFAULT_THRESHOLD_SMALL);
	}

	public void startMonitor(RoughnessLocationListener listener) {
		locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0,
				0, locationListener);
		sensorManager.registerListener(accelerometerListener, accelerometer,
				SensorManager.SENSOR_DELAY_GAME);
		this.listener = listener;

	}

	public void stopMonitor() {
		locationManager.removeUpdates(locationListener);
		sensorManager.unregisterListener(accelerometerListener);
	}
	
	public boolean isGpsEnabled(){
		return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
	}

	private SensorEventListener accelerometerListener = new SensorEventListener() {

		@Override
		public void onSensorChanged(SensorEvent event) {
			if (Math.abs(event.values[1]) >= thresholdSmall && Math.abs(event.values[1]) > yValue) {
				// new roughness detected with bigger acceleration
				yValue = Math.abs(event.values[1]);
				roughnessTime = event.timestamp / 1000000; // convert to millis
				Log.d(TAG, "Bigger roughness detected with value: " + yValue);
			}
			listener.onAccelerationChange(event.values[1]);
		}

		@Override
		public void onAccuracyChanged(Sensor sensor, int accuracy) {

		}
	};

	private LocationListener locationListener = new LocationListener() {

		@Override
		public void onStatusChanged(String provider, int status, Bundle extras) {

		}

		@Override
		public void onProviderEnabled(String provider) {

		}

		@Override
		public void onProviderDisabled(String provider) {

		}

		@Override
		public void onLocationChanged(Location location) {
			listener.onLocationChange(location);
			if (flag++ % 2 == 0)
				prevLocation = location;
			else
				currLocation = location;

			if (yValue > 0) {
				// roughness was detected notify activity
				// determine which location to use
				if (currLocation!=null){
					if (Math.abs(roughnessTime - prevLocation.getTime()) >= Math
							.abs(roughnessTime - currLocation.getTime())) {
						listener.onRoughnessDetected(currLocation, yValue);
					} else {
						listener.onRoughnessDetected(prevLocation, yValue);
					}
				} else {
					listener.onRoughnessDetected(prevLocation, yValue);
				}
				yValue = 0; //value was passed
			}
		}
	};

	private GpsStatus.Listener gpsListener = new GpsStatus.Listener() {

		@Override
		public void onGpsStatusChanged(int event) {
			listener.onGpsStatusChange(locationManager.getGpsStatus(null));

		}
	};

	private OnSharedPreferenceChangeListener preferenceListener = new OnSharedPreferenceChangeListener() {

		@Override
		public void onSharedPreferenceChanged(
				SharedPreferences sharedPreferences, String key) {
			if (key.equals(SettingsActivity.KEY_THRESHOLD_SMALL)) {
				thresholdSmall = sharedPreferences.getFloat(
						SettingsActivity.KEY_THRESHOLD_SMALL, 1);
			}
		}
	};

}
